"""
@File    :  ssh_test_layout.py
@Author  :  LeeSen
@Date    :  2024-06-27
@Version :  Python 3.7.4
"""
from time import sleep
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QGridLayout, \
    QPushButton, QComboBox, QMessageBox
from common_config_param import GlobalParam
from common_function import welcome_init, ip_format_check, int_num_check, text_input_check, log_format_print, clear_log
from ssh_client import SshClient


class SshClientThread(QThread):
    _signal = pyqtSignal(dict)

    def __init__(self, ip, port, timeout, username, password, continuous_execution,
                 client_name, command_list, print_flag):
        super().__init__()

        self.host_ip = ip
        self.host_port = port
        self.timeout = timeout
        self.username = username
        self.password = password
        self.continuous_execution = continuous_execution
        self.client_name = client_name
        self.command_list = command_list
        self.print_flag = print_flag
        self.stop_flag = False

    def run(self):
        run_times = 1
        res = {"code": "200", "message": "SSH Test Start", "client-name": self.client_name}
        self._signal.emit(res)
        while not self.stop_flag:
            with SshClient(self.host_ip, self.host_port, self.username, self.password, self.timeout) as ssh_c:
                if ssh_c == 1001:
                    res["code"] = 404
                    res["message"] = "Username or Password error"
                    self._signal.emit(res)
                elif ssh_c == 1002:
                    res["code"] = 404
                    res["message"] = "Connect time out"
                    self._signal.emit(res)
                elif ssh_c == 1003:
                    res["code"] = 404
                    res["message"] = "Unknown error"
                    self._signal.emit(res)
                else:
                    res["code"] = "200"
                    res["message"] = "SSH Test running " + str(run_times) + " times"
                    self._signal.emit(res)
                    sleep(0.5)
                    for command in self.command_list:
                        data_msg = ssh_c.excute_command(command)
                        if data_msg is None:
                            res = {"code": "404", "message": "Excute Command Error", "client-name": self.client_name}
                            self._signal.emit(res)
                            self.stop_flag = True
                            return
                        else:
                            if self.print_flag:
                                res["code"] = "202"
                                res["message"] = data_msg
                                self._signal.emit(res)
                        sleep(1)
            run_times += 1
            if not self.continuous_execution:
                break
        res = {"code": "200", "message": "SSH Test Stop", "client-name": self.client_name}
        self._signal.emit(res)

    def stop(self):
        self.stop_flag = True


class SshTestLayout(QVBoxLayout):
    def __init__(self):
        super().__init__()

        self.thread_list = []

        top_layout = QHBoxLayout()

        config_param_layout = QGridLayout()

        self.start_button = QPushButton('Start')
        self.start_button.clicked.connect(self.start_test)
        self.start_button.setEnabled(True)
        self.stop_button = QPushButton('Stop')
        self.stop_button.clicked.connect(self.stop_test)
        self.stop_button.setEnabled(False)

        config_param_label = QLabel("Config Param")

        test_mode_label = QLabel("Mode:")
        self.test_mode_input = QComboBox()
        self.test_mode_input.addItem("Login By Password")

        target_ip_label = QLabel('DUT IP Address:')
        self.target_ip_input = QLineEdit()
        self.target_ip_input.setText("192.168.56.102")

        ssh_port_label = QLabel("SSH Port:[1-65535]")
        self.ssh_port_input = QLineEdit()
        self.ssh_port_input.setText("22")

        ssh_timeout_label = QLabel("SSH Timeout(s):[1-60]")
        self.ssh_timeout_input = QLineEdit()
        self.ssh_timeout_input.setText("10")

        username_label = QLabel("UserName:")
        self.username_input = QLineEdit()
        self.username_input.setText("root")

        password_label = QLabel("Password:")
        self.password_input = QLineEdit()
        self.password_input.setText("123")

        client_num_label = QLabel("Client Number:[1-16]")
        self.client_num_input = QLineEdit()
        self.client_num_input.setText("1")

        continuous_execution_label = QLabel("Round-robin execution:")
        self.continuous_execution_box = QComboBox()
        self.continuous_execution_box.addItem("Yes")
        self.continuous_execution_box.addItem("No")

        print_config_label = QLabel("Print the switch:")
        self.print_config_box = QComboBox()
        self.print_config_box.addItem("OFF")
        self.print_config_box.addItem("ON")

        self.clear_log_button = QPushButton('Clear Log')
        self.clear_log_button.clicked.connect(lambda x: clear_log(self.log_area))

        config_param_layout.addWidget(config_param_label, 0, 0)

        config_param_layout.addWidget(self.start_button, 0, 4)
        config_param_layout.addWidget(self.stop_button, 0, 5)

        config_param_layout.addWidget(test_mode_label, 1, 0)
        config_param_layout.addWidget(self.test_mode_input, 1, 1)

        config_param_layout.addWidget(self.clear_log_button, 1, 5)

        config_param_layout.addWidget(target_ip_label, 2, 0)
        config_param_layout.addWidget(self.target_ip_input, 2, 1)
        config_param_layout.addWidget(ssh_port_label, 3, 0)
        config_param_layout.addWidget(self.ssh_port_input, 3, 1)
        config_param_layout.addWidget(ssh_timeout_label, 4, 0)
        config_param_layout.addWidget(self.ssh_timeout_input, 4, 1)
        config_param_layout.addWidget(client_num_label, 5, 0)
        config_param_layout.addWidget(self.client_num_input, 5, 1)

        config_param_layout.addWidget(username_label, 1, 2)
        config_param_layout.addWidget(self.username_input, 1, 3)
        config_param_layout.addWidget(password_label, 2, 2)
        config_param_layout.addWidget(self.password_input, 2, 3)

        config_param_layout.addWidget(continuous_execution_label, 3, 2)
        config_param_layout.addWidget(self.continuous_execution_box, 3, 3)
        config_param_layout.addWidget(print_config_label, 4, 2)
        config_param_layout.addWidget(self.print_config_box, 4, 3)

        padding_label = QLabel()
        config_param_layout.addWidget(padding_label, 6, 0)

        config_param_layout.setContentsMargins(10, 10, 10, 10)
        config_param_layout.setSpacing(10)

        top_layout.addLayout(config_param_layout)

        command_layout = QVBoxLayout()

        command_label = QLabel("Command:")
        self.command_area = QTextEdit()
        self.command_area.setPlaceholderText("需要执行的命令，按行分隔命令")

        command_layout.addWidget(command_label)
        command_layout.addWidget(self.command_area)

        self.addLayout(top_layout)
        self.addLayout(command_layout)

        log_label = QLabel("Real-time Logs")
        self.log_area = QTextEdit()
        self.log_area.setPlaceholderText("Log区域")
        self.log_area.setReadOnly(True)

        self.addWidget(log_label)
        self.addWidget(self.log_area)

        welcome_init(self.log_area)

    def config_param_check(self):
        host_ip = self.target_ip_input.text()
        if ip_format_check(host_ip):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid IP",
                                "The entered IP address is invalid.")
            return True
        host_port = self.ssh_port_input.text()
        if int_num_check(host_port) or (int(host_port) < 1 or int(host_port) > 65535):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid SSH Port",
                                "The entered SSH Port is invalid.[1-65535]")
            return True
        time_out = self.ssh_timeout_input.text()
        if int_num_check(time_out) or (int(time_out) < 1 or int(time_out) > 60):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid Time Out Param",
                                "The entered Time Out Param is invalid.[1-60]")
            return True
        username = self.username_input.text()
        if text_input_check(username):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid username",
                                "The entered username is invalid.")
            return True
        password = self.password_input.text()
        if text_input_check(password):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid password",
                                "The entered password is invalid.")
            return True
        command_list = self.command_area.toPlainText().splitlines()
        if len(command_list) == 0:
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid Command",
                                "The entered Command is invalid.")
            return True
        client_num = self.client_num_input.text()
        if int_num_check(client_num) or (int(client_num) < 1 or int(client_num) > 16):
            QMessageBox.warning(self.parentWidget().parentWidget(),
                                "Invalid Client Number",
                                "The entered Client Number is invalid. [1-16]")
            return True
        return False

    def start_test(self):
        if GlobalParam.global_running_flag:
            QMessageBox.warning(self.parentWidget().parentWidget(), "WARNING",
                                "Other programs are running, please stop first")
            return
        if self.config_param_check():
            return

        command_list = self.command_area.toPlainText().splitlines()
        continuous_execution = True if self.continuous_execution_box.currentText() == "Yes" else False
        print_config_flag = True if self.print_config_box.currentText() == "ON" else False

        client_num = int(self.client_num_input.text())
        GlobalParam.global_running_flag = True
        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)
        for i in range(client_num):
            item = SshClientThread(self.target_ip_input.text(),
                                   int(self.ssh_port_input.text()),
                                   int(self.ssh_timeout_input.text()),
                                   self.username_input.text(),
                                   self.password_input.text(),
                                   continuous_execution,
                                   "Client-" + str(i+1),
                                   command_list,
                                   print_config_flag)
            item._signal.connect(self.update_message_or_data)
            self.thread_list.append(item)
        for item in self.thread_list:
            item.start()

    def update_message_or_data(self, res):
        if res["code"] == "404":
            self.stop_test()
            log_format_print(self.log_area, res["client-name"] + ":" + res["message"])
        elif res["code"] == "202":
            log_format_print(self.log_area, res["message"])
        elif res["code"] == "200":
            log_format_print(self.log_area, res["client-name"] + ":" + res["message"])

    def stop_test(self):
        for item in self.thread_list:
            item.stop()
        for item in self.thread_list:
            while item.isRunning():
                item.stop()
        self.thread_list.clear()
        GlobalParam.global_running_flag = False
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        log_format_print(self.log_area, "SSH Test Stop")
